/* Copyright (C) 
 * 
 * Disclaim
 * This program is the property of AI Speech Ltd. It shall be communicated to
 * authorized personnel only. It is not to be disclosed outside the group without
 * prior written consent. If you are not sure if you’re authorized to read this
 * program, please contact info@aispeech.com before reading.
 * 
 */

#include "wtk/utils/wtk_utils_ustr.h"
#include "wtk/core/wtk_str_encode.h"
#include "wtk/utils/wtk_utils.h"
#include <ctype.h>


wtk_utils_ustr_t* wtk_utils_ustr_new(char *data, int len, int inplace) {
    wtk_utils_ustr_t *ustr = wtk_calloc(1, sizeof(wtk_utils_ustr_t));
    ustr->heap = wtk_heap_new(256);
    ustr->arr = wtk_array_new_h(ustr->heap, len, sizeof(wtk_utils_wrd_range_t*));

    if(1==inplace) {
        ustr->data = data;
        ustr->len = len;
    } else {
        ustr->data = wtk_heap_dup_data(ustr->heap, data, len);
        ustr->len = len;
    }

    // build utf8 word sequence
    wtk_utils_wrd_range_t *range = NULL;

    int i; 
    int sz;
    for(i=0; i<len; ) {
        sz = wtk_utf8_bytes(data[i]);
        range = wtk_heap_zalloc(ustr->heap, sizeof(wtk_utils_wrd_range_t));
        range->beg = i;
        range->len = sz;

        wtk_array_push2(ustr->arr, &range);

        i+=sz;
    }

    return ustr;
}



int wtk_utils_ustr_delete(wtk_utils_ustr_t *ustr) {
    wtk_heap_delete(ustr->heap);
    wtk_free(ustr);

    return 0;
}



wtk_string_t wtk_utils_ustr_at(wtk_utils_ustr_t *ustr, int i) {
    wtk_string_t str;
    str.data = NULL;
    str.len = 0;

    if(i<0 || i>=ustr->arr->nslot) {
        goto end;
    }

    wtk_utils_wrd_range_t *range = wtk_utils_array_get_val(ustr->arr, i, wtk_utils_wrd_range_t*);
    
    str.data = ustr->data+range->beg;
    str.len = range->len;

end:
    return str;
}



wtk_string_t wtk_utils_ustr_substr(wtk_utils_ustr_t *ustr, int fir, int lst) {
    wtk_string_t str;
    str.data = NULL;
    str.len = 0;

    if(fir>lst) {
        wtk_utils_warn("invalid range: [%d, %d]", fir, lst);
        goto end;
    }

    if(fir<0) {
        fir = 0;
    }

    if(lst>=ustr->arr->nslot) {
        lst = ustr->arr->nslot-1;
    }

    wtk_utils_wrd_range_t *rangeF = wtk_utils_array_get_val(ustr->arr, fir, wtk_utils_wrd_range_t*);;
    wtk_utils_wrd_range_t *rangeL = wtk_utils_array_get_val(ustr->arr, lst, wtk_utils_wrd_range_t*);;

    str.data = ustr->data + rangeF->beg;
    str.len = rangeL->beg-rangeF->beg+rangeL->len;

end:
    return str;
}


static const char* _strNums = "零幺一两二三四五六七八九十壹贰叁肆伍陆柒捌玖拾廿";
static const char* _strUnits = "十百千万亿点佰仟";

int wtk_utils_uchar_is_num(char *data, int len) {
    if(NULL==data || len<1) {
        return 0;
    }

    if(1==len) {
        return *data>='0' && *data<='9';
    } else {
        return -1!=wtk_str_str((char*)_strNums, strlen(_strNums), data, len);
    }
}

int wtk_utils_uchar_to_num(char *data, int len) {
    if(wtk_utils_str_equ("零", data, len)) {
        return 0;
    } else if(wtk_utils_str_equ("一", data, len) || wtk_utils_str_equ("幺", data, len) || wtk_utils_str_equ("壹", data, len)) {
        return 1;
    } else if(wtk_utils_str_equ("二", data, len) || wtk_utils_str_equ("两", data, len) || wtk_utils_str_equ("贰", data, len)) {
        return 2;
    } else if(wtk_utils_str_equ("三", data, len) || wtk_utils_str_equ("叁", data, len)) {
        return 3;
    } else if(wtk_utils_str_equ("四", data, len) || wtk_utils_str_equ("肆", data, len)) {
        return 4;
    } else if(wtk_utils_str_equ("五", data, len) || wtk_utils_str_equ("伍", data, len)) {
        return 5;
    } else if(wtk_utils_str_equ("六", data, len) || wtk_utils_str_equ("陆", data, len)) {
        return 6;
    } else if(wtk_utils_str_equ("七", data, len) || wtk_utils_str_equ("柒", data, len)) {
        return 7;
    } else if(wtk_utils_str_equ("八", data, len) || wtk_utils_str_equ("捌", data, len)) {
        return 8;
    } else if(wtk_utils_str_equ("九", data, len) || wtk_utils_str_equ("玖", data, len)) {
        return 9;
    } else {
        return -1;
    }
}


int wtk_utils_uchar_is_unit(char *data, int len) {
    if(3!=len) {
        return 0;
    } else {
        return -1!=wtk_str_str((char*)_strUnits, strlen(_strUnits), data, len);
    }
}


int wtk_utils_uchar_is_num_unit(char *data, int len) {
    return wtk_utils_uchar_is_num(data, len) || wtk_utils_uchar_is_unit(data, len);
}


int wtk_utils_ustr_is_num(wtk_utils_ustr_t *ustr) {
    int i;
    int sz;
    wtk_string_t val;

    sz = wtk_utils_ustr_get_num(ustr);
    for(i=0; i<sz; ++i) {
        val = wtk_utils_ustr_at(ustr, i);
        if(0==wtk_utils_uchar_is_num_str(&val)) {
            return 0;
        }
    }

    return 1;
}


int wtk_utils_ustr_is_unit(wtk_utils_ustr_t *ustr) {
    int i;
    int sz;
    wtk_string_t val;

    sz = wtk_utils_ustr_get_num(ustr);
    for(i=0; i<sz; ++i) {
        val =wtk_utils_ustr_at(ustr, i);
        if(0==wtk_utils_uchar_is_unit_str(&val)) {
            return 0;
        }
    }

    return 1;
}


int wtk_utils_ustr_is_num_unit(wtk_utils_ustr_t *ustr) {
    int i;
    int sz;
    wtk_string_t val;

    sz = wtk_utils_ustr_get_num(ustr);
    for(i=0; i<sz; ++i) {
        val =wtk_utils_ustr_at(ustr, i);
        if(0==wtk_utils_uchar_is_num_unit_str(&val)) {
            return 0;
        }
    }

    return 1;
}


int wtk_utils_str_is_num(char *data, int len) {
    wtk_str_iter_t iter = wtk_utf8_iter(data, len);
    wtk_string_t val = wtk_str_iter_next(&iter);
    for(; val.len>0; val=wtk_str_iter_next(&iter)) {
        if(0==wtk_utils_uchar_is_num(val.data, val.len)) {
            return 0;
        }
    }

    return 1;
}


int wtk_utils_str_is_unit(char *data, int len) {
    wtk_str_iter_t iter = wtk_utf8_iter(data, len);
    wtk_string_t val = wtk_str_iter_next(&iter);
    for(; val.len>0; val=wtk_str_iter_next(&iter)) {
        if(0==wtk_utils_uchar_is_unit(val.data, val.len)) {
            return 0;
        }
    }

    return 1;
}


int wtk_utils_str_is_num_unit(char *data, int len) {
    wtk_str_iter_t iter = wtk_utf8_iter(data, len);
    wtk_string_t val = wtk_str_iter_next(&iter);
    for(; val.len>0; val=wtk_str_iter_next(&iter)) {
        if(0==wtk_utils_uchar_is_num_unit(val.data, val.len)) {
            return 0;
        }
    }

    return 1;
}


int wtk_utils_uchar_is_word(char *data, int len) {
    if (len == 1) {
        if (!isalnum(data[0])) {
            return 0;
        }
    } else {
        if ((data[0] == 0xa1 && data[1] <= 0xfe && data[1] >= 0xa2) || (data[0] == 0xa3 && data[1] <= 0xfe && data[1] >= 0xa1)) {
            return 0;
        }
    }

    return 1;
}



int wtk_utils_uchar_is_eng(char *data, int len) {
    int sz;
    char *ptr = data;
    char *ptrEnd = data+len;
    for(; ptr && ptr<ptrEnd; ptr+=sz) {
        sz = wtk_utf8_bytes(*ptr);
        if(sz>1) {
            return 0;
        }

        if( ('a'<=*ptr && *ptr<='z') || ('A'<=*ptr && *ptr<='Z') || '\''==*ptr ) {
            continue;
        } else {
            return 0;
        }
    }

    if(1==len && data[0]=='\'') {
        return 0;
    } else {
        return 1;
    }
}



int wtk_utils_ustr_word_to_num(char *data, int len, wtk_strbuf_t *buf, int reset) {
    if(reset) {
        wtk_strbuf_reset(buf);
    }

    if(NULL==data || len<1) {
        return 0;
    }

    wtk_utils_ustr_t *ustr = wtk_utils_ustr_new(data, len, 1);
    int i;
    int ival;
    int state = 0;
    int numWord = wtk_utils_ustr_get_num(ustr);

    wtk_string_t str;
    wtk_string_t strNext;

    for(i=0; i<numWord; ++i) {
        str = wtk_utils_ustr_at(ustr, i);
        strNext = wtk_utils_ustr_at(ustr, i+1);

        // 处理单位
        if(wtk_utils_uchar_is_unit_str(&str)) {
           if(0==state) {
               // 开头的单位不用处理,但是十除外，十五
               if(wtk_utils_str_equ("十", str.data, str.len) &&  wtk_utils_uchar_is_num_str(&strNext)) {
                   wtk_strbuf_push_f(buf, "%s", "1");
                   state = 1;
               } else {
                   wtk_strbuf_push(buf, str.data, str.len);
               }
            } else {
                // 中间的单位不用处理, 五十一 => 51
                continue;
            }
        } else {
            state = 1;
            ival = wtk_utils_uchar_to_num_str(&str);
            if(-1!=ival) {
                wtk_strbuf_push_f(buf, "%d", wtk_utils_uchar_to_num_str(&str));
            } else {
                wtk_utils_warn("failed to trans uchar [%.*s] to number", str.len, str.data);
                wtk_strbuf_push(buf, str.data, str.len);
            }
        }
    }

    // 最后一个如果是单位，十(二十),补零
    if(wtk_utils_uchar_is_unit_str(&str) && 1==state) {
        if(wtk_utils_str_equ("十", str.data, str.len)) {
            wtk_strbuf_push_f(buf, "0");
        } else if(wtk_utils_str_equ("百", str.data, str.len) || wtk_utils_str_equ("佰", str.data, str.len)) {
            wtk_strbuf_push_f(buf, "00");
        } else if(wtk_utils_str_equ("千", str.data, str.len) || wtk_utils_str_equ("仟", str.data, str.len)) {
            wtk_strbuf_push_f(buf, "000");
        } else if(wtk_utils_str_equ("万", str.data, str.len)) {
            wtk_strbuf_push_f(buf, "万");
        } else if(wtk_utils_str_equ("亿", str.data, str.len)) {
            wtk_strbuf_push_f(buf, "亿");
        }
    }

    wtk_utils_ustr_delete(ustr);
    return 0;
}


int wtk_utils_ustr_trans_num(char *data, int len, wtk_strbuf_t *buf) {
    wtk_strbuf_reset(buf);

    wtk_utils_ustr_t *ustr = wtk_utils_ustr_new(data, len, 1);
    wtk_string_t str;

    wtk_strbuf_t *numBuf = wtk_strbuf_new(128, 1.0);
    wtk_strbuf_reset(numBuf);

    int i;
    int ret = 0;
    for(i=0; i<wtk_utils_ustr_get_num(ustr); ++i) {
        str = wtk_utils_ustr_at(ustr, i);

        if(wtk_utils_uchar_is_num_str(&str) || wtk_utils_uchar_is_unit_str(&str)) {
            wtk_strbuf_push(numBuf, str.data, str.len);
        } else {
            if(numBuf->pos>0) {
                ret = 1;
            }
            wtk_utils_ustr_word_to_num(numBuf->data, numBuf->pos, buf, 0);
            wtk_strbuf_reset(numBuf);
            wtk_strbuf_push_f(buf, "%.*s", str.len, str.data);
        }
    }

    wtk_utils_ustr_word_to_num(numBuf->data, numBuf->pos, buf, 0);

    wtk_strbuf_delete(numBuf);
    wtk_utils_ustr_delete(ustr);

    return ret;
}
